/*
 * @Author: wuqingchun
 * @Date: 2024-05-20 16:16:05
 * @Description: 线程变量使用
 * @LastEditors: wuqingchun
 * @LastEditTime: 2024-05-22 15:50:20
 */

#include <thread>
#include <vector>
#include "threadlocal_wrapper.h"

struct ThreadData
{
    ThreadData()
    {
        uiThreadIndex = 0;
        uiValue = 0;
        printf("%s\n", __FUNCTION__);
    }
    
    ThreadData(uint32_t uiIndex, uint32_t uiVal):
        uiThreadIndex(uiIndex),
        uiValue(uiVal)
    {
        printf("%s\n", __FUNCTION__);
    }

    ~ThreadData()
    {
        printf("%s\n", __FUNCTION__);
    }
    
    uint32_t uiThreadIndex;
    uint32_t uiValue;
};

struct ThreadData2
{
    ThreadData2(uint32_t uiIndex, uint32_t uiVal):
        uiThreadIndex(uiIndex),
        uiValue(uiVal)
    {
        printf("%s\n", __FUNCTION__);
    }

    ~ThreadData2()
    {
        printf("%s\n", __FUNCTION__);
    }

    uint32_t uiThreadIndex;
    uint32_t uiValue;
};

thread_local ThreadData2 g_stThreadData {0, 0};

void test_use_cpp()
{
    printf("%s begin\n", __FUNCTION__);
    std::vector<std::thread> vecThreads;
    volatile bool bRunning = true;

    for (uint32_t i = 0; i < 2; i++)
    {
        vecThreads.push_back(std::thread([&bRunning, i](){
            printf("%s: thread is running\n", __FUNCTION__);
            
            static thread_local ThreadData stTData = {i, 0};

            g_stThreadData.uiThreadIndex = i;

            while (bRunning)
            {
                stTData.uiValue++;
            }

            printf("Thread exit, %u, %u\n", stTData.uiThreadIndex, stTData.uiValue);
        }));
    }

    std::this_thread::sleep_for(std::chrono::seconds(2));

    bRunning = false;
    for(auto& refThread : vecThreads)
    {
        refThread.join();
    }
    printf("%s end\n", __FUNCTION__);
}

void test_use_pthread()
{
    printf("%s begin\n", __FUNCTION__);

    ThreadLocalWrapper<ThreadData> objTLS;
    pthread_once_t stOnce = PTHREAD_ONCE_INIT;

    std::vector<std::thread> vecThreads;
    volatile bool bRunning = true;

    ThreadData aTData[2];

    if (!objTLS.IsOk())
    {
        printf("ThreadLocalWrapper error\n");
        return;
    }

    for (uint32_t i = 0; i < 2; i++)
    {
        vecThreads.push_back(std::thread([&bRunning, i, &objTLS, &aTData, &stOnce](){
            printf("%s: thread is running\n", __FUNCTION__);
            
            // 不同线程数据共享同一缓存线，导致缓存失效，性能下降
            // aTData[i].uiThreadIndex = i;
            // aTData[i].uiValue = 0;
            
            ThreadData stTData {i, 0};
            if (objTLS.Set(&stTData) != 0)
            {
                printf("ThreadLocalWrapper Set error\n");

                return;
            }

            ThreadData* pstTData = nullptr;
            if (pstTData == nullptr)
            {
                pstTData = objTLS.Get();
            }

             if (pstTData == nullptr)
            {
                printf("error\n");
                return;
            }

            while (bRunning)
            {
                pstTData->uiValue++;
            }

            printf("Thread exit, %u, %u\n", pstTData->uiThreadIndex, pstTData->uiValue);
        }));
    }

    std::this_thread::sleep_for(std::chrono::seconds(2));

    bRunning = false;
    for(auto& refThread : vecThreads)
    {
        refThread.join();
    }

    printf("%s end\n", __FUNCTION__);
}


int main(int argc, char** argv)
{
    printf("%s begin\n", __FUNCTION__);

    //test_use_pthread();
    test_use_cpp();

    printf("%s end\n", __FUNCTION__);
    return 0;
}